package feizhou.untils.tools;

import org.apache.log4j.Logger;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * @version :
 * @Description :
 * @Autor : xiongjinpeng jpx_011@163.com
 * @Date : 2016年10月21日 下午2:25:07
 */
public class SerializeUtil {

    private static Logger log = Logger.getLogger(SerializeUtil.class);

    /**
     * 序列化对象
     *
     * @param object
     * @return
     */
    public static byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        byte[] bytes = null;
        try {
            // 序列化
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            bytes = baos.toByteArray();
        } catch (Exception e) {
            log.error("SerializeUtil serialize exception", e);
        } finally {
            close(oos);
            close(baos);
        }
        return bytes;
    }

    /**
     * 反序列化对象
     *
     * @param bytes
     * @return
     */
    public static Object unserialize(byte[] bytes) {
        Object obj = null;
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            // 反序列化
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            obj = ois.readObject();
        } catch (Exception e) {
            log.error("SerializeUtil serialize exception", e);
        } finally {
            close(bais);
            close(ois);
        }
        return obj;
    }

    /**
     * 关闭的数据源或目标。调用 close()方法可释放对象保存的资源（如打开文件）
     * 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流，则调用此方法无效。
     *
     * @param closeable
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (Exception e) {
                log.error("Unable to close closeable", e);
            }
        }
    }

    /**
     * 列表序列化（用于Redis整存整取）
     *
     * @param value
     * @return
     * @author: lijiayu
     * @date: 2019-08-23 15:45
     */
    public static <T> byte[] serialize(List<T> value) {
        if (value == null) {
            throw new NullPointerException("Can't serialize null");
        }
        byte[] rv = null;
        ByteArrayOutputStream bos = null;
        ObjectOutputStream os = null;
        try {
            bos = new ByteArrayOutputStream();
            os = new ObjectOutputStream(bos);
            for (T obj : value) {
                os.writeObject(obj);
            }
            os.writeObject(null);
            os.close();
            bos.close();
            rv = bos.toByteArray();
        } catch (IOException e) {
            throw new IllegalArgumentException("Non-serializable object", e);
        } finally {
            close(os);
            close(bos);
        }
        return rv;
    }

    /**
     * 反序列化列表（用于Redis整存整取）
     *
     * @param in
     * @return
     * @author: lijiayu
     * @date: 2019-08-23 15:45
     */
    public static <T> List<T> unserializeForList(byte[] in) {
        List<T> list = new ArrayList<T>();
        ByteArrayInputStream bis = null;
        ObjectInputStream is = null;
        try {
            if (in != null) {
                bis = new ByteArrayInputStream(in);
                is = new ObjectInputStream(bis);
                while (true) {
                    T obj = (T) is.readObject();
                    if (obj == null) {
                        break;
                    } else {
                        list.add(obj);
                    }
                }
            }
        } catch (IOException e) {
            log.error("Caught IOException decoding " + (in == null ? 0 : in.length) + " bytes of data", e);
        } catch (ClassNotFoundException e) {
            log.error("Caught CNFE decoding " + (in == null ? 0 : in.length) + " bytes of data", e);
        } finally {
            close(is);
            close(bis);
        }
        return list;
    }

	/**
	 * Base64 方式Encode byte数组转字符串
	 *
	 * @param bytes
	 * @return
	 */
	public static String encodeBytesToStr(byte[] bytes) {
		return Base64.getEncoder().encodeToString(bytes);
	}


	/**
	 * Base64 方式decode 字符串转byte数组
	 *
	 * @param key
	 * @return
	 */
	public static byte[] decodeStr(String key) {
		return Base64.getDecoder().decode(key.getBytes(StandardCharsets.UTF_8));
	}

	/**
	 * 字符串转byte数组
	 *
	 * @param key
	 * @return
	 */
	public static byte[] strToBytes(String key) {
		return key.getBytes(StandardCharsets.UTF_8);
	}

	/**
	 * 中文字符串转byte数组
	 *
	 * @param key
	 * @return
	 */
	public static String chinaStrToBytes(String key) {
		return key.getBytes(StandardCharsets.UTF_8).toString();
	}
}
